package com.letao.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.letao.server.dto.BatchSpuInfoDTO;
import com.letao.server.dto.EsSpuInfoDTO;
import com.letao.server.dto.PageDTO;
import com.letao.server.dto.Result;
import com.letao.server.entity.OrderDetail;
import com.letao.server.entity.SkuCommentInfo;
import com.letao.server.entity.SkuInfo;
import com.letao.server.entity.SpuInfo;
import com.letao.server.mapper.OrderDetailMapper;
import com.letao.server.mapper.SkuCommentInfoMapper;
import com.letao.server.mapper.SpuInfoMapper;
import com.letao.server.service.IBaseCategoryService;
import com.letao.server.service.ISkuService;
import com.letao.server.service.ISpuService;
import jakarta.annotation.Resource;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfo> implements ISpuService {
    @Resource
    SpuInfoMapper spuInfoMapper;
    @Resource
    RestHighLevelClient client;

    @Resource
    private IBaseCategoryService baseCategoryService;

    @Resource
    private SkuCommentInfoMapper skuCommentInfoMapper;

    @Resource
    private ISkuService skuService;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    /**
     * 分页查询spu信息
     *
     * @param spuName       spu名称
     * @param oneCategoryId 一级分类id
     * @param twoCategoryId 二级分类id
     * @param keyWords      关键字
     * @param page          页码
     * @param pageSize      页大小
     * @return 返回的结果
     */
    @Override
    public Result getPageInfo(Long id, String spuName, Integer oneCategoryId, Integer twoCategoryId, String keyWords, Integer hasStock, Integer page, Integer pageSize) {
        QueryWrapper<SpuInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("bit", 1);
        if (spuName != null) wrapper.like("spu_name", spuName);
        if (oneCategoryId != null) wrapper.eq("one_category_id", oneCategoryId);
        if (twoCategoryId != null) wrapper.eq("two_category_id", twoCategoryId);
        if (keyWords != null) wrapper.like("key_words", keyWords);
        if (id != null) wrapper.likeRight("id", id);

        IPage<SpuInfo> shopPage = new Page<>(page, pageSize);
        IPage<SpuInfo> shopInfoIPage2 = spuInfoMapper.selectPage(shopPage, wrapper);
        List<BatchSpuInfoDTO> batchSpuInfoDTOList = new ArrayList<>();

        for (SpuInfo record : shopInfoIPage2.getRecords()) {
            //更新库存状态
            List<SkuInfo> skuInfoList = skuService.query().eq("spu_id", record.getId()).list();
            for (SkuInfo skuInfo : skuInfoList) {
                if (skuInfo.getStock() > 0) {
                    record.setHasStock(1);
                    updateById(record);
                }
            }
        }
        if (hasStock != null) wrapper.eq("has_stock", hasStock);

        IPage<SpuInfo> shopInfoIPage = spuInfoMapper.selectPage(shopPage, wrapper);
        for (SpuInfo record : shopInfoIPage.getRecords()) {
            BatchSpuInfoDTO batchSpuInfoDTO = BeanUtil.copyProperties(record, BatchSpuInfoDTO.class);

            batchSpuInfoDTO.setStock(0L);
            batchSpuInfoDTO.setHasStock(0);
            batchSpuInfoDTO.setSkuNames(" ");
            batchSpuInfoDTO.setOneCategoryName(baseCategoryService.getById(record.getOneCategoryId()).getName());
            batchSpuInfoDTO.setTwoCategoryName(baseCategoryService.getById(record.getTwoCategoryId()).getName());
            //查询评论数
            QueryWrapper<SkuCommentInfo> commentWrapper = new QueryWrapper<>();
            commentWrapper.eq("spu_id", record.getId()).select("count(*) as count");
            List<Map<String, Object>> maps1 = skuCommentInfoMapper.selectMaps(commentWrapper);
            if (maps1.get(0) != null) batchSpuInfoDTO.setCommentNum((Long) maps1.get(0).get("count"));
            //查询库存
            QueryWrapper<SkuInfo> skuWrapper = new QueryWrapper<>();
            skuWrapper.eq("spu_id", record.getId());
            List<SkuInfo> skuInfoList = skuService.query().eq("spu_id", record.getId()).list();
            String skuNames = new String("");
            for (SkuInfo skuInfo : skuInfoList) {
                batchSpuInfoDTO.setStock(batchSpuInfoDTO.getStock() + skuInfo.getStock());
                skuNames = skuInfo.getSkuName() + "," + skuNames;
            }

            skuNames = skuNames.substring(0, Math.max(0, skuNames.length() - 1));
            batchSpuInfoDTO.setSkuNames(skuNames);

            QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("sum(amount) as sales");
            queryWrapper.eq("spu_id", record.getId());
            List<Map<String, Object>> maps = orderDetailMapper.selectMaps(queryWrapper);
            if (maps.get(0) != null) {
                String sales = maps.get(0).get("sales").toString();
                batchSpuInfoDTO.setSales(Long.valueOf(sales));
            }
            batchSpuInfoDTO.setHasStock(record.getHasStock());
            batchSpuInfoDTOList.add(batchSpuInfoDTO);

        }
        if (hasStock != null) wrapper.eq("has_stock", hasStock);
        IPage<SpuInfo> shopInfoIPage1 = spuInfoMapper.selectPage(shopPage, wrapper);

        PageDTO<BatchSpuInfoDTO> batchSpuInfoPageDTO = new PageDTO<>();
        batchSpuInfoPageDTO.setRows(batchSpuInfoDTOList);
        batchSpuInfoPageDTO.setTotalSize(shopInfoIPage1.getTotal());
        batchSpuInfoPageDTO.setPages(shopInfoIPage1.getPages());
        batchSpuInfoPageDTO.setPageSize(shopInfoIPage1.getSize());
        batchSpuInfoPageDTO.setCurrentPage(shopInfoIPage1.getCurrent());
        return Result.success(batchSpuInfoPageDTO);
    }

    /**
     * 查询推荐spu
     *
     * @param query    查询字段
     * @param page     页码
     * @param pageSize 页大小
     * @return 返回的结果
     */
    @Override
    public Result suggest(String query, Integer page, Integer pageSize) {
        try {
            SearchRequest request = new SearchRequest("spu");
            if ("".equals(query))
                request.source().query(QueryBuilders.matchAllQuery());
            else
                request.source().query(QueryBuilders.matchQuery("all", query));
            request.source().from((page - 1) * pageSize).size(pageSize);
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits searchHits = response.getHits();
            long total = searchHits.getTotalHits().value;
            long pages = Math.ceilDivExact(total, pageSize);
            SearchHit[] hits = searchHits.getHits();
            List<EsSpuInfoDTO> list = new ArrayList<>();
            for (SearchHit hit : hits) {
                String json = hit.getSourceAsString();
                EsSpuInfoDTO dto = JSON.parseObject(json, EsSpuInfoDTO.class);
                dto.setKeyWords(null);
                dto.setSuggection(null);
                dto.setOneCategoryId(null);
                dto.setTwoCategoryId(null);
                list.add(dto);
            }
            PageDTO<EsSpuInfoDTO> dto = new PageDTO<>();
            dto.setRows(list);
            dto.setCurrentPage(Long.valueOf(page));
            dto.setTotalSize(total);
            dto.setPages(pages);
            dto.setPageSize(Long.valueOf(pageSize));
            return Result.success(dto);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 补全推荐字段
     *
     * @param query 待补全文字
     * @return 返回的结果
     */
    @Override
    public Result complete(String query) {
        try {
            SearchRequest request = new SearchRequest("spu");
            request.source().suggest(new SuggestBuilder().addSuggestion(
                    "suggestion",
                    SuggestBuilders.completionSuggestion("suggection")
                            .prefix(query)
                            .skipDuplicates(true)
                            .size(10)
            ));
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Suggest suggest = response.getSuggest();
            CompletionSuggestion suggections = suggest.getSuggestion("suggestion");
            List<CompletionSuggestion.Entry.Option> options = suggections.getOptions();
            List<String> list = new ArrayList<>();
            for (CompletionSuggestion.Entry.Option option : options) {
                String string = option.getText().toString();
                list.add(string);
            }
            return Result.success(list);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result hotSpu() {
        QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("sum(amount) as sale, spu_id as spu");
        queryWrapper.groupBy("spu_id");
        queryWrapper.orderByDesc("sale");
        List<Map<String, Object>> maps = orderDetailMapper.selectMaps(queryWrapper);
        List<SpuInfo> list = new ArrayList<>();
        for (int i = 0; i < Math.min(maps.size(), 8); i++) {
            SpuInfo spu = getById((Serializable) maps.get(i).get("spu"));
            list.add(spu);
        }
        if (list.size() < 8) {
            QueryWrapper<SpuInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("bit", 1);
            wrapper.orderByDesc("create_time");
            wrapper.last("limit " + (8 - list.size()));
            List<SpuInfo> spuInfos = spuInfoMapper.selectList(wrapper);
            list.addAll(spuInfos);
        }
        return Result.success(list);
    }
}
